package com.waqu.common.utils.abtester;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.waqu.common.utils.collection.ArrayMapTools;
import com.waqu.common.utils.other.WeightRandom;
import com.waqu.common.utils.security.EncryptionTools;
import com.waqu.common.utils.text.StringTools;

/**
 * @Title FlowController.java
 * @Package com.waqu.common.utils.abtester
 * @author Administrator
 * @date 2015年5月5日 下午5:54:36
 * @version V1.0
 */
public class FlowController {

	private List<Flow> algorithm;
	private String module;

	/**
	 * 创建ABTest分流工具
	 * 
	 * @param module
	 *            需要测试项目名称，唯一标识
	 * @param algorithm
	 */
	public FlowController(String module, List<Flow> algorithm) {
		if (StringTools.isEmpty(module) || ArrayMapTools.isEmpty(algorithm))
			throw new NullPointerException();
		if (ArrayMapTools.lessThan(algorithm, 2))
			throw new IllegalStateException();

		this.algorithm = algorithm;
		this.module = module;
	}

	/**
	 * 当前用户是否能测试当前算法【一部分用户】
	 * 
	 * @Title abTester
	 * @param name
	 *            算法名称
	 * @param uid
	 *            用户ID
	 * @return boolean true可进行测试
	 */
	public boolean abTester(String name, String uid) {
		int has = EncryptionTools.SHA256(uid.toUpperCase() + this.module).hashCode();
		int total = 0;
		for (Flow flow : algorithm) {
			total += flow.getWeight();
		}

		String tester = null;
		int des = has % total + 1, tmp = 1;
		des = des < 0 ? 0 - des : des;
		for (Flow flow : algorithm) {
			if (tmp <= des && des <= tmp + flow.getWeight()) {
				tester = flow.getName();
				break;
			} else
				tmp += flow.getWeight();
		}
		return StringTools.isNotEmpty(tester) && tester.equalsIgnoreCase(name);
	}

	/**
	 * 所有用户进行算法测试
	 * 
	 * @Title allABTester
	 * @param name
	 * @param uid
	 * @return boolean
	 */
	public boolean allABTester(String name, String uid) {
		Map<String, Integer> weightMaps = new HashMap<>();
		for (Flow flow : algorithm) {
			int des = EncryptionTools.SHA256(uid.toUpperCase() + this.module + name).hashCode();
			des = des < 0 ? 0 - des : des;
			weightMaps.put(flow.getName(), des + flow.getWeight());
		}
		String tester = WeightRandom.calculate(weightMaps);
		return StringTools.isNotEmpty(tester) && tester.equalsIgnoreCase(name);
	}
}
